package utils

import (
	"bufio"
	"fastdp-ops/cmd/agent/zaplog"
	pb "fastdp-ops/proto/machine"
	"fmt"
	"github.com/shirou/gopsutil/v3/cpu"
	"github.com/shirou/gopsutil/v3/disk"
	"github.com/shirou/gopsutil/v3/host"
	"github.com/shirou/gopsutil/v3/mem"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

// 获取真实机器环境信息
func GetRealEnvInfo() (*pb.MachineEnvInfo, error) {
	// 1. 主机信息
	hostInfo, err := host.Info()
	if err != nil {
		return nil, err
	}

	// 2. CPU信息
	cpuInfo, err := cpu.Info()
	if err != nil {
		return nil, err
	}
	// 取第一个CPU的型号（多CPU通常型号一致）
	var cpuModel string
	if len(cpuInfo) > 0 {
		cpuModel = cpuInfo[0].ModelName
	}
	cpuCores, _ := cpu.Counts(true) // 总核心数（含逻辑核心）

	// 3. 内存信息
	memInfo, err := mem.VirtualMemory()
	if err != nil {
		return nil, err
	}

	// 4. 磁盘信息（只取本地磁盘）

	disks, err := getDiskInfo()
	if err != nil {
		disks = []*pb.DiskInfo{}
	}
	return &pb.MachineEnvInfo{
		Hostname: hostInfo.Hostname,
		Uptime:   formatUptime(hostInfo.Uptime), // 转换为"23h5m"格式
		Os: &pb.SystemInfo{
			Name:    GetLinuxDistribution(),
			Version: hostInfo.PlatformVersion,
			Kernel:  hostInfo.KernelVersion,
			Arch:    hostInfo.KernelArch,
		},
		Cpu: &pb.CpuInfo{
			Model: cpuModel,
			Cores: int32(cpuCores),
		},
		Memory: &pb.MemoryInfo{
			TotalMb: int64(memInfo.Total / 1024 / 1024 / 1024), // 转换为GB
			FreeMb:  int64(memInfo.Free / 1024 / 1024 / 1024),
			UsedMb:  int64(memInfo.Used / 1024 / 1024 / 1024),
		},
		Disks: disks,
	}, nil
}

// 辅助函数：格式化运行时间（秒 -> "23h5m10s"）
func formatUptime(seconds uint64) string {
	d := time.Duration(seconds) * time.Second
	return d.String()
}

func getDiskInfo() ([]*pb.DiskInfo, error) {
	blockDir := "/sys/block"
	entries, err := os.ReadDir(blockDir)
	if err != nil {
		return nil, fmt.Errorf("读取块设备目录失败: %v", err)
	}
	var disks []*pb.DiskInfo
	for _, entry := range entries {
		deviceName := entry.Name()
		if strings.HasPrefix(deviceName, "dm-") || strings.HasPrefix(deviceName, "loop") {
			continue // 跳过所有以 dm- loop 开头的设备
		}
		devicePath := filepath.Join("/dev", deviceName)
		diskType, err := getDiskType(deviceName)
		if err != nil {
			// 无法判断时默认未知类型，不中断整体获取
			diskType = "unknown"
			zaplog.Logger.Sugar().Errorf("警告：无法判断磁盘类型 %s: %v", devicePath, err)
		}
		totalGB, err := getDiskTotalSize(devicePath)
		if err != nil {
			// 忽略获取失败的磁盘（如虚拟设备）
			zaplog.Logger.Sugar().Errorf("警告：无法获取磁盘容量 %s: %v\n", devicePath, err)
			continue
		}
		disks = append(disks, &pb.DiskInfo{
			Device:  deviceName,
			Type:    diskType,
			TotalGb: totalGB,
		})

	}
	return disks, nil

}
func getDiskType(deviceName string) (string, error) {
	rotationalPath := filepath.Join("/sys/block", deviceName, "queue", "rotational")
	file, err := os.Open(rotationalPath)
	if err != nil {
		return "", fmt.Errorf("打开 rotational 文件失败: %v", err)
	}
	defer file.Close()

	// 读取文件内容（0 或 1）
	scanner := bufio.NewScanner(file)
	scanner.Scan()
	rotationalStr := scanner.Text()
	rotational, err := strconv.Atoi(rotationalStr)
	if err != nil {
		return "", fmt.Errorf("解析 rotational 值失败: %v", err)
	}

	if rotational == 0 {
		return "ssd", nil
	}
	return "hdd", nil
}

// 获取磁盘总容量（GB）
func getDiskTotalSize(devicePath string) (int64, error) {
	// 通过 gopsutil 获取磁盘使用信息（总容量）
	usage, err := disk.Usage(devicePath)
	if err != nil {
		return 0, fmt.Errorf("获取磁盘使用信息失败: %v", err)
	}

	// 转换为 GB（1GB = 1024^3 字节）
	totalGB := int64(usage.Total / 1024 / 1024 / 1024)
	return totalGB, nil
}

// getLinuxDistribution 从 /etc/os-release 解析发行版名称
func GetLinuxDistribution() string {
	// 打开发行版信息文件（Linux 标准路径）
	file, err := os.Open("/etc/os-release")
	if err != nil {
		return "unknown"
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "PRETTY_NAME") {
			return strings.Trim(strings.TrimPrefix(line, "PRETTY_NAME="), "\"")
		}
	}

	// 未找到 PRETTY_NAME 时返回未知
	return "unknown"
}
